package burp;

import burp.Utils.HintTextField;
import burp.Utils.LoggerUtils;
import burp.Utils.StatusTableCellRenderer;

import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.util.*;
import java.util.List;
import java.util.concurrent.CountDownLatch;

public class ParamNullifierHistory implements ITab {
    private final JPanel mainPanel;
    private final JLabel testStatusLabel = new JLabel(" ");

    // 原始请求表格和模型
    private final JTable originalTable;
    private final DefaultTableModel originalModel;

    // 置空请求表格和模型
    private final JTable nullifiedTable;
    private final DefaultTableModel nullifiedModel;

    // 请求/响应查看器
    private final JTextArea requestViewer;
    private final JTextArea responseViewer;

    // 存储数据
    private final List<IHttpRequestResponse> originalRequests;
    private final List<IHttpRequestResponse> nullifiedRequests;

    public ParamNullifierHistory(List<IHttpRequestResponse> originalRequests) {
        // 创建副本，避免引用污染
        this.originalRequests = new ArrayList<>(originalRequests);
        this.nullifiedRequests = new ArrayList<>();

        mainPanel = new JPanel(new BorderLayout());

        // 初始化原始请求表格
        originalModel = new DefaultTableModel(new Object[]{"ID", "Method", "URL", "Status", "Length"}, 0);
        originalTable = new JTable(originalModel);
        originalTable.setAutoCreateRowSorter(true);

        // 初始化置空请求表格
        nullifiedModel = new DefaultTableModel(new Object[]{"ID", "Method", "URL", "Status", "Length"}, 0);
        nullifiedTable = new JTable(nullifiedModel);
        nullifiedTable.setAutoCreateRowSorter(true);

        // 将 this 作为 client property 存储
        nullifiedTable.putClientProperty("history", this);

        // 对每列设置渲染器
        for (int i = 0; i < nullifiedModel.getColumnCount(); i++) {
            nullifiedTable.getColumnModel().getColumn(i).setCellRenderer(new StatusTableCellRenderer());
        }

        // 请求/响应查看器
        requestViewer = createTextViewer("Request");
        responseViewer = createTextViewer("Response");

        JSplitPane viewerSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
        viewerSplit.setTopComponent(new JScrollPane(requestViewer));
        viewerSplit.setBottomComponent(new JScrollPane(responseViewer));
        viewerSplit.setResizeWeight(0.5);

        // 表格面板（上下布局）
        JPanel tablePanel = new JPanel(new GridLayout(2, 1));
        tablePanel.add(new JScrollPane(originalTable));
        tablePanel.add(new JScrollPane(nullifiedTable));
        // 左侧两个表格，右侧详情
        JSplitPane mainSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
        mainSplit.setLeftComponent(tablePanel);
        mainSplit.setRightComponent(viewerSplit);
        mainSplit.setResizeWeight(0.6);

        // 按钮面板
        JPanel buttonPanel = getButtonPanel(originalRequests);

        // 添加到主面板
        mainPanel.add(buttonPanel, BorderLayout.NORTH);
        mainPanel.add(mainSplit, BorderLayout.CENTER);

        // 注册事件监听器
        registerSelectionListeners();
    }

    private JPanel getButtonPanel(List<IHttpRequestResponse> originalRequests) {
        // 清空按钮
        JButton clearButton = new JButton("Clear");
        clearButton.addActionListener(e -> clearAll());

        // Settings 按钮
        JButton settingsButton = new JButton("Settings");
        settingsButton.addActionListener(e -> showSettingsDialog());

        // Test 按钮
        JButton testButton = new JButton("Test");
        testButton.addActionListener(e -> {
            if (originalRequests.isEmpty()) {
                JOptionPane.showMessageDialog(mainPanel, "原始请求列表为空，请先添加请求。");
                return;
            }

            SwingUtilities.invokeLater(() -> testStatusLabel.setText("执行中..."));

            // 后台执行多个异步任务
            new SwingWorker<Void, Void>() {

                @Override
                protected Void doInBackground() throws Exception {
                    int totalRequests = originalRequests.size();
                    // 创建 CountDownLatch，用于等待所有任务完成
                    CountDownLatch latch = new CountDownLatch(totalRequests);

                    for (IHttpRequestResponse message : originalRequests) {
                        if (message == null || message.getRequest() == null) {
                            latch.countDown();
                            continue;
                        }

                        // 异步操作传入回调
                        BurpExtender.getInstance().testAllNullifiedParams(message, latch::countDown);
                    }

                    // 等待所有任务完成
                    latch.await();

                    return null;
                }

                @Override
                protected void done() {
                    LoggerUtils.info("所有请求已处理完成");
                    SwingUtilities.invokeLater(() -> testStatusLabel.setText("测试完成"));
                }
            }.execute();
        });

        // 按钮布局
        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 5, 5));
        buttonPanel.add(clearButton);
        buttonPanel.add(settingsButton);
        buttonPanel.add(testButton);
        buttonPanel.add(testStatusLabel);

        return buttonPanel;
    }

    private void registerSelectionListeners() {
        // 原始请求表格选择监听器
        originalTable.getSelectionModel().addListSelectionListener(e -> {
            int selectedRow = originalTable.getSelectedRow();
            if (selectedRow >= 0 && selectedRow < originalRequests.size()) {
                nullifiedTable.clearSelection();
                IHttpRequestResponse selectedMessage = originalRequests.get(selectedRow);
                updateDetailView(selectedMessage);
            }
        });

        // 置空请求表格选择监听器
        nullifiedTable.getSelectionModel().addListSelectionListener(e -> {
            int selectedRow = nullifiedTable.getSelectedRow();
            if (selectedRow >= 0 && selectedRow < nullifiedRequests.size()) {
                originalTable.clearSelection();
                IHttpRequestResponse selectedMessage = nullifiedRequests.get(selectedRow);
                updateDetailView(selectedMessage);
            }
        });
    }

    private void updateDetailView(IHttpRequestResponse message) {
        requestViewer.setText(BurpExtender.getInstance().getHelpers().bytesToString(message.getRequest()));
        responseViewer.setText(message.getResponse() != null ?
                BurpExtender.getInstance().getHelpers().bytesToString(message.getResponse()) : "无响应内容");
    }

    private JTextArea createTextViewer(String title) {
        JTextArea textArea = new JTextArea();
        textArea.setEditable(false);
        textArea.setFont(new Font("Monospaced", Font.PLAIN, 12));
        textArea.setBorder(BorderFactory.createTitledBorder(title));
        return textArea;
    }

    // 添加原始请求
    public void addOriginalEntry(IHttpRequestResponse response) {
        if (response == null || response.getRequest() == null) return;

        // 深拷贝请求对象
        IHttpRequestResponse originalRes = BurpExtender.getInstance().getCallbacks().saveBuffersToTempFiles(response);

        IRequestInfo reqInfo = BurpExtender.getInstance().getHelpers()
                .analyzeRequest(originalRes.getHttpService(), originalRes.getRequest());
        IResponseInfo resInfo = originalRes.getResponse() != null ?
                BurpExtender.getInstance().getHelpers().analyzeResponse(originalRes.getResponse()) : null;

        originalRequests.add(originalRes);
        originalModel.addRow(new Object[]{
                originalModel.getRowCount() + 1,
                reqInfo.getMethod(),
                reqInfo.getUrl(),
                resInfo != null ? resInfo.getStatusCode() : 0,
                originalRes.getResponse() != null ? originalRes.getResponse().length : 0
        });
    }

    // 添加置空请求
    public void addNullifiedEntry(IHttpRequestResponse response) {
        if (response == null || response.getRequest() == null) return;

        IRequestInfo reqInfo = BurpExtender.getInstance().getHelpers()
                .analyzeRequest(response.getHttpService(), response.getRequest());
        IResponseInfo resInfo = response.getResponse() != null ?
                BurpExtender.getInstance().getHelpers().analyzeResponse(response.getResponse()) : null;

        nullifiedRequests.add(response);

        nullifiedModel.addRow(new Object[]{
                nullifiedModel.getRowCount() + 1,
                reqInfo.getMethod(),
                reqInfo.getUrl(),
                resInfo != null ? resInfo.getStatusCode() : 0,
                response.getResponse() != null ? response.getResponse().length : 0
        });
    }

    private void clearAll() {
        SwingUtilities.invokeLater(() -> {
            originalModel.setRowCount(0);
            nullifiedModel.setRowCount(0);
            originalRequests.clear();
            nullifiedRequests.clear();
            requestViewer.setText("");
            responseViewer.setText("");
            BurpExtender.getInstance().clearOriginalRequests();
            LoggerUtils.info("History cleared");
        });
    }

    /**
     * 刷新置空请求表格的状态码列（第4列）
     */
    private void refreshStatusColumn() {
        SwingUtilities.invokeLater(() -> {
            if (nullifiedTable.getRowCount() > 0) {
                Rectangle rect = nullifiedTable.getCellRect(0, 3, false);
                int lastRow = nullifiedTable.getRowCount() - 1;
                rect.add(nullifiedTable.getCellRect(lastRow, 3, false));
                nullifiedTable.repaint(rect);
            }
        });
    }

    /**
     * 根据行号获取对应的请求对象
     */
    public IHttpRequestResponse getNullifiedRequest(int row) {
        if (row >= 0 && row < nullifiedRequests.size()) {
            return nullifiedRequests.get(row);
        }
        return null;
    }

    private void showSettingsDialog() {
        // Headers配置项
        JPanel dialogPanel = new JPanel(new BorderLayout());
        JPanel inputPanel = new JPanel(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        JLabel headerLabel = new JLabel("指定置空的 Headers (逗号分隔):");
        JTextField headerField = new JTextField(30);  // 指定宽度
        // 初始化字段内容为当前 TARGET_HEADERS
        if (!BurpExtender.TARGET_HEADERS.isEmpty()) {
            headerField.setText(String.join(",", BurpExtender.TARGET_HEADERS));
        }
        // 设置 Label 的约束条件
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.anchor = GridBagConstraints.WEST;
        gbc.insets = new Insets(5, 5, 5, 10);
        inputPanel.add(headerLabel, gbc);
        // 设置 TextField 的约束条件
        gbc.gridx = 1;
        gbc.weightx = 1.0;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        inputPanel.add(headerField, gbc);

        // Cookie 配置项
        JLabel cookieLabel = new JLabel("指定置空的 Cookies (逗号分隔):");
        JTextField cookieField = new JTextField(30);
        if (!BurpExtender.TARGET_COOKIES.isEmpty()) {
            cookieField.setText(String.join(",", BurpExtender.TARGET_COOKIES));
        }
        gbc.gridy = 1; // 下一行
        gbc.gridx = 0;
        gbc.anchor = GridBagConstraints.WEST;
        gbc.insets = new Insets(5, 5, 5, 10);
        inputPanel.add(cookieLabel, gbc);
        gbc.gridx = 1;
        gbc.weightx = 1.0;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        inputPanel.add(cookieField, gbc);
        dialogPanel.add(inputPanel, BorderLayout.CENTER);

        // URL参数配置项
        JLabel urlParamLabel = new JLabel("指定置空的 URL 参数 (逗号分隔):");
        HintTextField urlParamField = new HintTextField("");
        gbc.gridy = 2;
        gbc.gridx = 0;
        gbc.anchor = GridBagConstraints.WEST;
        gbc.insets = new Insets(5, 5, 5, 10);
        inputPanel.add(urlParamLabel, gbc);
        gbc.gridx = 1;
        gbc.weightx = 1.0;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        inputPanel.add(urlParamField, gbc);

        // Body参数配置项
        JLabel bodyParamLabel = new JLabel("指定置空的 Body 参数 (逗号分隔):");
        HintTextField bodyParamField = new HintTextField("");
        gbc.gridy = 3;
        gbc.gridx = 0;
        gbc.anchor = GridBagConstraints.WEST;
        gbc.insets = new Insets(5, 5, 5, 10);
        inputPanel.add(bodyParamLabel, gbc);
        gbc.gridx = 1;
        gbc.weightx = 1.0;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        inputPanel.add(bodyParamField, gbc);

        // 提示标签1
        JLabel hintLabel1 = new JLabel("提示1：默认将自动识别所有 URL 和 Body 参数，并依次置空。");
        gbc.gridy = 4;
        gbc.gridx = 0;
        gbc.gridwidth = 2;
        gbc.anchor = GridBagConstraints.WEST;
        gbc.insets = new Insets(5, 5, 5, 10);
        inputPanel.add(hintLabel1, gbc);

        // 分割线
        JSeparator separator = new JSeparator(SwingConstants.HORIZONTAL);
        gbc.gridy = 5;
        gbc.gridx = 0;
        gbc.gridwidth = 2;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.insets = new Insets(10, 5, 10, 5);
        inputPanel.add(separator, gbc);

        // 响应码检查复选框
        JCheckBox checkStatusBox = new JCheckBox("检查响应码为 5XX");
        checkStatusBox.setSelected(BurpExtender.CHECK_RESPONSE_CODE);
        gbc.gridy = 6;
        gbc.gridx = 0;
        gbc.gridwidth = 2;
        gbc.anchor = GridBagConstraints.WEST;
        gbc.insets = new Insets(5, 5, 5, 10);
        inputPanel.add(checkStatusBox, gbc);

        // 预期响应内容关键词输入框
        JLabel expectedResLabel = new JLabel("预期响应内容（逗号分隔）:");
        JTextField expectedResField = new JTextField(30);
        if (!BurpExtender.CUSTOM_RESPONSE_INDICATORS.isEmpty()) {
            expectedResField.setText(String.join(",", BurpExtender.CUSTOM_RESPONSE_INDICATORS));
        }
        gbc.gridy = 7;
        gbc.gridx = 0;
        gbc.anchor = GridBagConstraints.WEST;
        gbc.insets = new Insets(5, 5, 5, 10);
        inputPanel.add(expectedResLabel, gbc);
        gbc.gridx = 1;
        gbc.weightx = 1.0;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        inputPanel.add(expectedResField, gbc);

        // 提示标签2
        JLabel hintLabel2 = new JLabel("提示2：测试请求包含配置的响应码或响应内容时，该行请求标红。");
        gbc.gridy = 8;
        gbc.gridx = 0;
        gbc.gridwidth = 2;
        gbc.anchor = GridBagConstraints.WEST;
        gbc.insets = new Insets(5, 5, 5, 10);
        inputPanel.add(hintLabel2, gbc);

        // 按钮面板
        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
        JButton okButton = new JButton("OK");
        JButton cancelButton = new JButton("Cancel");

        // OK按钮事件
        okButton.addActionListener(e -> {
            // Headers配置
            String headersText = headerField.getText().trim();
            Set<String> newHeaders = new HashSet<>();
            if (!headersText.isEmpty()) {
                Arrays.stream(headersText.split(","))
                        .map(String::trim)
                        .filter(h -> !h.isEmpty())
                        .forEach(newHeaders::add);
            }
            // Cookie配置
            String cookiesText = cookieField.getText().trim();
            Set<String> newCookies = new HashSet<>();

            if (!cookiesText.isEmpty()) {
                Arrays.stream(cookiesText.split(","))
                        .map(String::trim)
                        .filter(c -> !c.isEmpty())
                        .forEach(newCookies::add);
            }

            // URL参数配置
            String urlParamsText = urlParamField.getText().trim();
            Set<String> newUrlParams = new HashSet<>();
            if (!urlParamsText.isEmpty()) {
                Arrays.stream(urlParamsText.split(","))
                        .map(String::trim)
                        .filter(u -> !u.isEmpty())
                        .forEach(newUrlParams::add);
            }

            // Body参数配置
            String bodyParamsText = bodyParamField.getText().trim();
            Set<String> newBodyParams = new HashSet<>();
            if (!bodyParamsText.isEmpty()) {
                Arrays.stream(bodyParamsText.split(","))
                        .map(String::trim)
                        .filter(b -> !b.isEmpty())
                        .forEach(newBodyParams::add);
            }

            // 更新响应码检查配置
            BurpExtender.CHECK_RESPONSE_CODE = checkStatusBox.isSelected();

            // 更新自定义响应特征配置
            String indicatorText = expectedResField.getText().trim();
            Set<String> newIndicators = new HashSet<>();
            if (!indicatorText.isEmpty()) {
                Arrays.stream(indicatorText.split(","))
                        .map(String::trim)
                        .filter(s -> !s.isEmpty())
                        .forEach(newIndicators::add);
            }

            // 更新静态集合
            BurpExtender.TARGET_COOKIES.clear();
            BurpExtender.TARGET_COOKIES.addAll(newCookies);
            BurpExtender.TARGET_HEADERS.clear();
            BurpExtender.TARGET_HEADERS.addAll(newHeaders);
            BurpExtender.TARGET_URL_PARAMS.clear();
            BurpExtender.TARGET_URL_PARAMS.addAll(newUrlParams);
            BurpExtender.TARGET_BODY_PARAMS.clear();
            BurpExtender.TARGET_BODY_PARAMS.addAll(newBodyParams);
            BurpExtender.CUSTOM_RESPONSE_INDICATORS.clear();
            BurpExtender.CUSTOM_RESPONSE_INDICATORS.addAll(newIndicators);
            refreshStatusColumn(); // 刷新状态码列
            LoggerUtils.info("Settings updated");

            Window window = SwingUtilities.getWindowAncestor(okButton);
            if (window instanceof Dialog) {
                window.dispose();
            }
        });

        // Cancel按钮事件
        cancelButton.addActionListener(e -> {
            LoggerUtils.info("Cancel clicked");
            Window window = SwingUtilities.getWindowAncestor(cancelButton);
            if (window instanceof Dialog) {
                window.dispose(); // 关闭窗口
            }
        });

        // 添加按钮
        buttonPanel.add(okButton);
        buttonPanel.add(cancelButton);

        // 添加到对话框面板
        dialogPanel.add(buttonPanel, BorderLayout.SOUTH);

        // 创建自定义 JDialog
        JDialog dialog = new JDialog(
                (Frame) SwingUtilities.getWindowAncestor(mainPanel),
                "Settings",
                true
        );
        dialog.setContentPane(dialogPanel);
        dialog.pack();
        dialog.setLocationRelativeTo(mainPanel);
        dialog.setVisible(true);
    }

    @Override
    public String getTabCaption() {
        return "ParamNullifier History";
    }

    @Override
    public Component getUiComponent() {
        return mainPanel;
    }
}
